﻿using System;
using System.Collections.Generic;
using System.Linq;
using BearUtil;
using BearUtil.Hidden;
using UnityEngine;
using XNode;

// dialog_moduel 数据解析类
public class DialogDataFormat
{
    /// <summary>
    /// 设置类型
    /// </summary>
    /// <param name="nt"></param>
    public static void SetData(out DialogData data, BearNode node)
    {
        data = new DialogData();
        var dataType = node.GetType();
        // Debug.Log("----------- : " + type.Name);

        //特殊处理几个不好处理的节点：StartNode, EndNode, TalkNode
        int type = (int) dataType.GetField("type").GetValue(node);
        data.type = type;
        if (type == (int) NodeType.START ||
            type == (int) NodeType.END)
        {
        }
        else if (type == (int) NodeType.TALK)
        {
            setTalkData(data, node as TalkNode);
        }
        else if (type == (int) NodeType.CHOICE)
        {
            setChoice(data, node as ChoiceNode);  
        }
        else
        {
            var infos = dataType.GetFields();
            for (int i = 0; i < infos.Length; i++)
            {
                try
                {
                    var info = infos[i];
                    // startwith "_" 表示不进入数据分析过程，自定义属性的辅助属性需求
                    if (!info.DeclaringType.Name.Equals(dataType.Name) || info.FieldType.Name.ToLower().Equals("audioclip") || info.Name.StartsWith("_"))
                        continue;

                    // 兼容旧代码
                    if (info.FieldType.Name.ToLower().Equals("vector2"))
                    {
                        // 临时跳过 PlayItemMerger
                        if(infos[i].Name.Equals("ProductPos"))
                            continue;

                        var propX = info.Name + "_x";
                        var propY = info.Name + "_y";
                        Vector2 pos = (Vector2)info.GetValue(node);
                        data.GetType().GetField(propX).SetValue(data, pos.x);
                        data.GetType().GetField(propY).SetValue(data, pos.y);
                    }
                    // 兼容旧代码
                    else if (info.FieldType.Name.ToLower().Equals("node"))
                    {
                        var nodes = (BearNode[])info.GetValue(node);
                        List<int> indexs = new List<int>();
                        for (int j = 0; j < nodes.Length; j++)
                        {
                            indexs.Add(nodes[j].index);
                        }
                        
                        data.GetType().GetField(info.Name).SetValue(data, indexs);
                    }
                    else
                    {
                        // 临时跳过 PlayItemMerger
                        if (infos[i].Name.Equals("Product") || infos[i].Name.Equals("Material1") || infos[i].Name.Equals("Material2"))
                            continue;
                        
                        data.GetType().GetField(info.Name).SetValue(data, info.GetValue(node));
                    }
                }
                catch (Exception e)
                {
                    Debug.LogError(string.Format("[DialogDataFormat] ---- error info:{0} : {1} ", infos[i].Name,
                        data.GetType().Name));
                    Debug.LogError(e);
                }
            }
        }
        data.id = node.index;
        data.back_step = (node as BearNode).isSaved ? 1 : 0;
        // choice(2) 和 end(-1) 节点不用 chlidNode
        if (data.type != (int)NodeType.CHOICE && data.type != (int)NodeType.END)
            setChildNode(data, node);
    }

    // 设置子节点数据
    private static void setChildNode(DialogData data, BearNode node)
    {
        List<int> children = new List<int>();
        var nextPort = node.Ports.Where(port => port.fieldName.Equals("next"))?.First();
        if (nextPort != null && nextPort.ConnectionCount > 0)
        {
            fillChildren(ref children, nextPort.GetConnections());
        }
        
        data.child_node = new int[1][];
        data.child_node[0] = children.ToArray();
    }

    /// <summary>
    /// 设置 TalkNode 的数据
    /// </summary>
    /// <param name="data"></param>
    /// <param name="tn"></param>
    private static void setTalkData(DialogData data, TalkNode tn)
    {
        if (tn.actor != null)
        {
            data.role_id = tn.actor.role_id;
            data.role_name = tn.role_name;
            data.icon_portrait = tn.icon_portrait == null || tn.icon_portrait.Equals("")
                ? new string[] {""}
                : new string[] {"#" + tn.icon_portrait};
    
            data.is_show_scene = tn.showOnScene;
        }
    
        data.scene_bubble = (int) tn.scene_bubble;
        data.lines_bubble = (int) tn.lines_bubble;
        data.icon_pic = tn.show_pic;
        data.lines_speed = (int) tn.FontSpeed;
        data.portrait_direction = (int) tn.portrait_direction;
        data.lines = tn.lines;

        data.voice = tn.VoicClip;
    }

    /// <summary>
    /// 选项节点
    /// </summary>
    /// <param name="node"></param>
    private static void setChoice(DialogData data, ChoiceNode node)
    {
        List<List<int>> nextPorts = new List<List<int>>();
        var nextP = node.Ports.GetEnumerator();
        while (nextP.MoveNext())
        {
            var port = nextP.Current;
            if (port.IsOutput && port.ConnectionCount > 0)
            {
                List<int> newChoice = new List<int>();
                fillChildren(ref newChoice, port.GetConnections());

                if (newChoice.Count > 0)
                    nextPorts.Add(newChoice);
            }
        }
        
        data.child_node = new int[nextPorts.Count][];
        for (int i = 0; i < nextPorts.Count; i++)
        {
            data.child_node[i] = nextPorts[i].ToArray();
        }

        // 赋值
        data.choose_text = node.choose.ToArray();
    }
    
    /// <summary>
    /// 填充子节点
    /// </summary>
    /// <param name="children"></param>
    /// <param name="ports"></param>
    private static void fillChildren(ref List<int> children, List<NodePort> ports)
    {
        for (int i = 0; i < ports.Count; i++)
        {
            var node = ports[i].node as BearNode;
            if (node == null)
                return;
            
            if (node.type == (int)NodeType.MERGE)
                children.Add((node.next as BearNode).index);
            else
                children.Add(node.index);
        }
    }
}